#ifndef db_CONNECTIONPOOL_H
#define db_CONNECTIONPOOL_H
#include <vector>
#include <string>
/*
#include <ace/Semaphore.h>
#include <ace/Thread_Mutex.h>
#include <ace/Lock.h>
#include <ace/Guard_T.h>
*/
#include <threading/Semaphore_.h>
#include <threading/RecursiveMutex.h>
#include <threading/Guard.h>

namespace serika
{
	namespace db
	{
		class Any;

		template<typename T>
		class ConnectionPool
		{
		public:
			ConnectionPool(size_t num);
			~ConnectionPool();
	
			bool Create(const Any& initInfo);
	
			T* GetConnection();
			void ReleaseConnection(T* conn);
	
			void Close();
	
		public:
			const std::vector<T*>& GetConnections() const { return mConnections; }
	
			const Any& GetInitInfo() const { return mInitInfo; }
	
		private:
			threading::Semaphore* mSem;
			threading::RecursiveMutex* mMutex;
			//ACE_Semaphore* mSem;
			//ACE_Thread_Mutex* mMutex;
			size_t mNum;
	
			std::vector<T*> mConnections;
			Any mInitInfo;
	
			//friend T;
	
			void Clear();
		};
	
		template<typename T>
		ConnectionPool<T>::ConnectionPool(size_t num)
			: mNum(num)
		{
			mSem = new threading::Semaphore(num);
			mMutex = new threading::RecursiveMutex;
			mConnections.reserve(num);
		}
	
		template<typename T>
		ConnectionPool<T>::~ConnectionPool()
		{
			{
				//ACE_GUARD(ACE_Thread_Mutex, guard, *mMutex);
				threading::RecursiveMutex::Guard guard(*mMutex);
				this->Clear();
			}
			delete mMutex;
			delete mSem;
		}
	
		template<typename T>
		void ConnectionPool<T>::Close()
		{
			//ACE_GUARD(ACE_Thread_Mutex, guard, *mMutex);
			threading::RecursiveMutex::Guard guard(*mMutex);
			this->Clear();
		}
	
		template<typename T>
		bool ConnectionPool<T>::Create(const Any& initInfo)
		{
			//ACE_GUARD_REACTION(ACE_Thread_Mutex, guard, *mMutex, false);
			threading::RecursiveMutex::Guard guard(*mMutex);
	
			mInitInfo = initInfo;
	
			bool ret = true;
			for (size_t i = 0; i < mNum; ++i)
			{
				T* conn = new T(*this);
				if (!conn->Create())
				{
					ret = false;
					delete conn;
					break;
				}
				mConnections.push_back(conn);
			}
	
			if (!ret)
			{
				this->Clear();
				mConnections.reserve(mNum);
			}
			return ret;
		}
	
		template<typename T>
		void ConnectionPool<T>::Clear()
		{
			for (typename std::vector<T*>::iterator itr = mConnections.begin(); itr != mConnections.end(); ++itr)
			{
				(*itr)->Close();
				delete *itr;
			}
			mConnections.clear();
		}
	
		template<typename T>
		T* ConnectionPool<T>::GetConnection()
		{
			mSem->Acquire();
			{
				//ACE_GUARD_REACTION(ACE_Thread_Mutex, guard, *mMutex, 0);
				threading::RecursiveMutex::Guard guard(*mMutex);
				T* conn = mConnections.back();
				if (conn->Test())
				{
					mConnections.pop_back();
					return conn;
				}
				if (conn->Reconnect())
				{
					mConnections.pop_back();
					return conn;
				}
				mSem->Release();
				return 0;
			}
		}
	
		template<typename T>
		void ConnectionPool<T>::ReleaseConnection(T* conn)
		{
			//ACE_GUARD(ACE_Thread_Mutex, guard, *mMutex);
			threading::RecursiveMutex::Guard guard(*mMutex);
			mConnections.push_back(conn);
			mSem->Release();
		}
	}
}
	
#endif

